/**
 * L'énumération du statut social 
 * @author Klelifa Sarah, Razavet Maël
 * @version 1.0
 */
package fr.eisti.ing1.projetgsiKlelifaRazavet.DataManager;

import fr.eisti.ing1.projetgsiKlelifaRazavet.Graphe.AreteValuee;
import fr.eisti.ing1.projetgsiKlelifaRazavet.Graphe.GrapheValuee;
import fr.eisti.ing1.projetgsiKlelifaRazavet.Objets.AEtudierA;
import fr.eisti.ing1.projetgsiKlelifaRazavet.Objets.ATravaillerA;
import fr.eisti.ing1.projetgsiKlelifaRazavet.Objets.Adresse;
import fr.eisti.ing1.projetgsiKlelifaRazavet.Objets.CentreInteret;
import fr.eisti.ing1.projetgsiKlelifaRazavet.Objets.Genre;
import fr.eisti.ing1.projetgsiKlelifaRazavet.Objets.Personne;
import fr.eisti.ing1.projetgsiKlelifaRazavet.Objets.Statut;
import fr.eisti.ing1.projetgsiKlelifaRazavet.Objets.Type;
import fr.eisti.sql.MyConnector;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * La classe qui gère le lien avec la base de donnée
 * @author Klelifa Sarah, Razavet Maël
 * @version 1.0
 */
public class DataManager {
    //liste récupérant toutes le modifications effectuer au cours de l'utilisation
    private static List<ArrayList<Integer>> modifications = new ArrayList<ArrayList<Integer>>();

    /**
     * Fonction qui gère l'ajout d'un ami ou la proposition d'un ami
     * @param idPersonne1 : personne proposant ou acceptant le lien d'amitié
     * @param idPersonne2 : personne associé a la proposition ou à l'acceptation du lien d'amitier
     */
    public static void create(int idPersonne1,int idPersonne2){
        //on créé une liste temporaire permettant d'ajouter la modification à la liste de modification
        ArrayList<Integer> listTmp = new ArrayList<Integer>();
        //1 signifie que l'on fait une création
        Collections.addAll(listTmp, 1,idPersonne1,idPersonne2);
        modifications.add(listTmp);
    }

    /**
     * Fonction gérant l'evaluation d'un lien d'amitié
     * @param idPersonne1 : personne evaluant son lien d'amitié
     * @param idPersonne2 : personne étant évalué
     * @param evaluation : note choisit par la personne evaluant
     */
    public static void update(int idPersonne1,int idPersonne2,int evaluation){
        //on créé une liste temporaire permettant d'ajouter la modification à la liste de modification
        ArrayList<Integer> listTmp = new ArrayList<Integer>();
        //2 signifie que l'on fait une modification
        Collections.addAll(listTmp, 2,idPersonne1,idPersonne2,evaluation);
        modifications.add(listTmp);

    }

    /**
     * Fonction gérant la suppression d'un lien d'amitié ou d'un ami dans la liste de proposition
     * @param idPersonne1 : personne supprimant le lien
     * @param idPersonne2 : personne associé au lien supprimé
     */
     public static void delete(int idPersonne1,int idPersonne2){
        //on créé une liste temporaire permettant d'ajouter la modification à la liste de modification
        ArrayList<Integer> listTmp = new ArrayList<Integer>();
        //3 signifie que l'on fait une suppression
        Collections.addAll(listTmp, 3,idPersonne1,idPersonne2);
        modifications.add(listTmp);
    }

     /**
      * Fonction permettant de sauvegarder les changements effectuer dans l'application dans la base de donnée
      */
     public static void synchronize(){
         //On créé une connection avec la base de données
        Connection connection;
        connection = MyConnector.getConnection();
        //on essaie de sauvegarder les modifications dans la base de données
        try {
            //On creer 3 requêtes : une pour la modification, une pour la suppression, une pour la creation
            PreparedStatement pUpdate = connection.prepareStatement("update EstAmiAvec set evaluation = ? where Personne_idPersonne1 = ? and Personne_idPersonne2 = ? ");
            PreparedStatement pDelete = connection.prepareStatement("delete from EstAmiAvec where Personne_idPersonne1 = ? and Personne_idPersonne2 = ? ");
            PreparedStatement pCreate = connection.prepareStatement("insert into EstAmiAvec values (?,?,-1)");

            //on parcout la liste de modification et on rempli la requête en fonction
            for(int i=0; i<modifications.size();i++){
                if(modifications.get(i).get(0) == 1){//creation
                    pCreate.setInt(1,modifications.get(i).get(1));
                    pCreate.setInt(2,modifications.get(i).get(2));
                    pCreate.executeUpdate();
                }else if(modifications.get(i).get(0) == 2){//modification
                    pUpdate.setInt(1,modifications.get(i).get(3));
                    pUpdate.setInt(2,modifications.get(i).get(1));
                    pUpdate.setInt(3,modifications.get(i).get(2));
                    pUpdate.executeUpdate();
                }else{//suppression
                    pDelete.setInt(1,modifications.get(i).get(1));
                    pDelete.setInt(2, modifications.get(i).get(2));
                    pDelete.executeUpdate();
                }
                 System.out.println("Modification effectuer");
            }
            //on commit les liens à la base de données
            connection.commit();
            //on ferme la connection
            connection.close();
           
        } catch (SQLException ex) {
            System.err.println("Erreur dans la sauvegarde dans la base de données");
            Logger.getLogger(DataManager.class.getName()).log(Level.SEVERE, null, ex);
        }

        
     }

    
     /**
      * Fonction gérant le chargment de la base de donnée en java, creant un resaux sociales
      * @param login : le login du client pour la base de données
      * @param password : le mot de passe du client pour la base de données
      * @param pServer : url du serveur
      * @param pPort : port du serveur
      * @return socialNetwork : le reseaux social correspondant aux informations de la base de données
      */
      public static GrapheValuee<Personne> loadData(String login, String password,String pServer, int pPort) {

            //On creer des listes temporaires pour récupérer toutes les informations importantes de la bdd
            ArrayList<Personne> personnes = new ArrayList<Personne>();
            ArrayList<AreteValuee<Personne>> arretes = new ArrayList<AreteValuee<Personne>>();
            ArrayList<AreteValuee<Personne>> arretesTmp = new ArrayList<AreteValuee<Personne>>();
            ArrayList<Adresse> adresses = new ArrayList<Adresse>();
            ArrayList<CentreInteret> centreInterets = new ArrayList<CentreInteret>();
            ArrayList<AEtudierA> etudes = new ArrayList<AEtudierA>();
            ArrayList<ATravaillerA> travailles = new ArrayList<ATravaillerA>();
            GrapheValuee<Personne> socialNetwork = new GrapheValuee<Personne>();
            //on créé une nouvelle connection
            Connection connection;
            MyConnector.setParametersClient(pServer,pPort,login, password);
            connection = MyConnector.getConnection();
           try { //on essaie de creer des objets avec les informations de la base de donnée
            //on creer un statement avec la base de données
            Statement state = connection.createStatement();
            //on récupère toutes les adresses de la bdd
            String requestAdresse = "select * from Adresse";
            ResultSet resAdresse = state.executeQuery(requestAdresse);
            //on les stockes dans la liste d'adresses
            while (resAdresse.next()) {
                Adresse a = new Adresse(resAdresse.getInt(1), resAdresse.getString(2), resAdresse.getString(3), resAdresse.getInt(4), resAdresse.getString(5));
                adresses.add(a);
            }
            
            //on va ensuite récupérer toutes les personnes de la base de donnée qui représente les utilisateurs du réseaux social
            String request = "select *  from Personne";
            ResultSet res = state.executeQuery(request);
            //on les stockes dans la liste de personnes
            while (res.next()) {
                Genre sexe;
                Statut statut;
                //on teste si le champs sexe et différent de null, si il est null on lui met nonAssigne
                if (res.getString("sexe") != null) {
                    sexe = Genre.valueOf(res.getString("sexe"));
                } else {
                    sexe = Genre.nonAssigne;
                }
                //on fait la meme chose pour le statut sociale, ce sont des champs non obligatoire donc il y a possibilité qu'ils soit null
                if (res.getString("statutSocial") != null) {
                    statut = Statut.valueOf(res.getString("statutSocial"));
                } else {
                    statut = Statut.nonAssigne;
                }
                Personne p = new Personne(res.getInt(1), res.getString(2), res.getString(3), sexe, res.getString(5), statut, res.getString(7));
                personnes.add(p);
            }
            
            //on associe une adresse de residence et une adresse de naisance aux personnes les ayant renseignés
            String requestAdressePersonne = "select Personne_idPersonne, Adresse_idAdresse, type  from Personne, SeSitueA where idPersonne = Personne_idPersonne";
            ResultSet resAdressePersonne = state.executeQuery(requestAdressePersonne);
            while (resAdressePersonne.next()) {
                //on parcours la liste d'adresse ainsi que la liste de personne et des que les id corresponds avec les id de la requete on ajoute l'adresse a la personne correspondante
                for (Adresse a : adresses) {
                    for (Personne p : personnes) {
                        if (p.getIdPersonne() == resAdressePersonne.getInt(1)) {
                            if (a.getIdAdresse() == resAdressePersonne.getInt(2)) {
                                p.getAdresses().put(Type.valueOf(resAdressePersonne.getString(3)), a);
                            }
                        }
                    }
                }
            }
            
            //On récupère tous les liens d'amitier afin de créer le reseau
            String request2 = "select * from EstAmiAvec";
            ResultSet res2 = state.executeQuery(request2);
            while (res2.next()) {
                for (Personne p : personnes) {
                    if (p.getIdPersonne() == res2.getInt(1)) {
                        for (Personne p2 : personnes) {
                            if (p2.getIdPersonne() == res2.getInt(2)) {
                                AreteValuee ar = new AreteValuee(p, p2, res2.getInt(3));
                                arretes.add(ar);
                            }
                        }
                    }
                }
            }
            
            //on recupere tous les parcours scolaires des personnes
            String request3 = "select Parcours_idParcours, Personne_idPersonne, Adresse_idAdresse, nomEtablissement, dateDebut, dateFin from Parcours p, AEtudierA a where p.idParcours = a.Parcours_idParcours";
            ResultSet res3 = state.executeQuery(request3);
            while (res3.next()) {
                Calendar dateFin;
                Adresse adresse;
                adresse = null;
                dateFin = null;
                //si la date n'est pas null on la converti en calendar
                if (res3.getString(6) != null) {
                    dateFin = toCalendar(res3.getString(6), "dd/MM/yyyy");
                }
                for (Adresse a : adresses) {
                    if (a.getIdAdresse() == res3.getInt(3)) {
                        adresse = a;
                    }
                }
                AEtudierA aea = new AEtudierA(res3.getInt(1), res3.getInt(2), res3.getString(4), toCalendar(res3.getString(5), "dd/MM/yyyy"), dateFin, adresse);
                etudes.add(aea);
            }
            
            //on recupere tous les parcours professionels des personnes
            String request4 = "select Parcours_idParcours,Adresse_idAdresse, Personne_idPersonne, nomEtablissement, dateDebut, dateFin, poste from Parcours p, ATravaillerA a where p.idParcours = a.Parcours_idParcours";
            ResultSet res4 = state.executeQuery(request4);
            while (res4.next()) {
                Calendar dateFin;
                Adresse adresse;
                adresse = null;
                dateFin = null;
                if (res4.getString(6) != null) {
                    dateFin = toCalendar(res4.getString(6), "dd/MM/yyyy");
                }
                for (Adresse a : adresses) {
                    if (a.getIdAdresse() == res4.getInt(2)) {
                        adresse = a;
                    }
                }
                ATravaillerA ata = new ATravaillerA(res4.getInt(1), res4.getInt(3), res4.getString(4), toCalendar(res4.getString(5), "dd/MM/yyyy"), dateFin, res4.getString(7), adresse);
                travailles.add(ata);
            }
            
            //on récupère tous les centre d'interet des personnes
            String requestCentreInteret = "select  CentreInteret_idCentreInteret, Personne_idPersonne, categorie, nomCentreInteret from CentreInteret ci, EstInteressePar eip where ci.idCentreInteret = eip.CentreInteret_idCentreInteret";
            ResultSet resCentreInteret = state.executeQuery(requestCentreInteret);
            while (resCentreInteret.next()) {
                CentreInteret ci = new CentreInteret(resCentreInteret.getInt(1), resCentreInteret.getInt(2), resCentreInteret.getString(3), resCentreInteret.getString(4));
                centreInterets.add(ci);
            }
            state.close();
            /**
             *on rempli notre reseau sociale : on parcours notre personne et suivant son ID on compare
             *avec les différentes liste et on lui ajoute a ses liste de professions, centre interet etc..
             */
            for (Personne p : personnes) {
                for (CentreInteret ci : centreInterets) {
                    if (ci.getIdPersonne() == p.getIdPersonne()) {
                        p.getCentreInterets().add(ci);
                        System.out.println(p.toString() + " est interessé par le/la " + ci.toString());
                    }
                }
                for (AEtudierA aea : etudes) {
                    if (aea.getIdPersonne() == p.getIdPersonne()) {
                        p.getEtudes().add(aea);
                        System.out.println(p.toString() + " a étudier a " + aea.toString());
                    }
                }
                for (ATravaillerA ata : travailles) {
                    if (ata.getIdPersonne() == p.getIdPersonne()) {
                        p.getTravailles().add(ata);
                        System.out.println(p.toString() + " a travailler a " + ata.toString());
                    }
                }
               
                System.out.println(p.toString() + " est nait à " + p.getAdresses().get(Type.Naissance));
                System.out.println(p.toString() + " vie à " + p.getAdresses().get(Type.Residence));
            }
            //on rempli le reseau social en y ajoutant les liens entre les différentes personnes
            Iterator<AreteValuee<Personne>> it;
            it = arretes.iterator();
            //on creer une liste temporaire d'arete afin de voir ou son les aretes dupliquer
            arretesTmp.addAll(arretes);
            //on va remplir notre reseau social en liant les personnes entre elles
            while (it.hasNext()) {
                AreteValuee<Personne> ar = it.next();
                Boolean proposePas;
                proposePas = false;
                Iterator<AreteValuee<Personne>> itTmp;
                itTmp = arretes.iterator();
                while (itTmp.hasNext() && !proposePas) {
                    AreteValuee<Personne> arTmp = itTmp.next();
                    //si il y a bien un lien dans les deux sense alors ils sont amis, sinon c'est juste une proposition
                    proposePas = (ar.getSommet1() == arTmp.getSommet2()) && (ar.getSommet2() == arTmp.getSommet1());
                    if (proposePas) {
                        AreteValuee<Personne> nvArete = new AreteValuee<Personne>(ar.getSommet1(), ar.getSommet2(), ar.getEvaluation());
                        socialNetwork.getEnsembleArete().add(nvArete);
                    }
                }
                if (!proposePas) {
                    ar.getSommet2().getPropositionAmi().add(ar.getSommet1());
                }
            }
            //on affiche la liste de proposition d'amis de chaque personne
            for (Personne p : personnes) {
                System.out.println(p.toString() + " sa liste Propose " + toStringProposition(p.getPropositionAmi()));
            }
            //on ajoute les utilisateurs au réseau
            socialNetwork.getUtilisateurs().addAll(personnes);
            //on ferme la connection
            MyConnector.closeConnection();
            connection.close();
            } catch (SQLException ex) {
            Logger.getLogger(DataManager.class.getName()).log(Level.SEVERE, null, ex);
            System.err.println("Erreur lors du chargement de la bdd");
        }

            return socialNetwork;


    }

    /**
     * Fonction permettant d'afficher une liste de proposition d'ami d'une personne
     * @param propositionAmi : la liste d'ami de la personne
     * @return res : une chaine de caractere
     */
    public static String toStringProposition(List<Personne> propositionAmi) {
        String res;
        res = " ";
        //on parcours la liste de proposition d'ami et on ajoute les amis à la chaine au fur et a mesure
        for(int i=0; i<propositionAmi.size();i++){
            res = res + propositionAmi.get(i).toString();
        }
        return res;
    }

    /**
     * Fonction permettant de changer une chaine de caractere en calendar
     * @param dateString : la date sous forme de chaine de caractere
     * @param pattern : le format associer sous forme de chaine de caractere
     * @return calendar : la date sous forme de calendar
     */
    public static Calendar toCalendar(String dateString, String pattern) {
        try {
          //on transforme notre chaine pattern en format
           SimpleDateFormat format = new SimpleDateFormat(pattern);
           //on parse notre date sous le format correspondant
           Date date = format.parse(dateString);
           //on la transforme en calendar
           Calendar calendar = Calendar.getInstance();
           calendar.setTime(date);
           return calendar;
        } catch (ParseException e) {
           throw new IllegalArgumentException(e);
        }
    }
    
    
}
